package com.wei.czz.common.po;

import com.wei.czz.common.tool.BaseEntity;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2023-02-18 21:58:40
 * className: SlideWindowPo 滑动窗口类
 * version: 1.0
 * description:
 *  此类仅供内部使用
 */
@Getter
@Setter
@Accessors(chain = true)
public class SlideWindowPo extends BaseEntity {

    /**
     * 解除限流时间戳
     * 空值时不限流
     */
    private volatile Long unLockTime;
    /**
     * 限流时回复消息
     */
    private volatile String message;
    /**
     * 请求限流配置对象
     */
    private volatile LimitConfigPo requestNode;
    /**
     * 异常限流配置对象
     */
    private volatile LimitConfigPo failNode;
    /**
     * 可重入锁对象
     * 公平锁
     */
    private ReentrantLock lock;

    public SlideWindowPo() {
        lock = new ReentrantLock(true);
    }

    /**
     * 请求限流计算操作
     */
    public void requestLimitMath() {
        long now = System.currentTimeMillis();

        if (unLockTime != null) {
            // 限流时间不为空
            if (unLockTime.compareTo(now) > 0) {
                // 请求被限流，直接返回
                return;
            }
            // 限流时间已过，恢复请求
            unLockTime = null;
            message = null;
        }
        if (requestNode == null) {
            // 没有请求限流配置，直接返回
            return;
        }
        // 加锁
        lock.lock();
        try {
            if (unLockTime != null && unLockTime.compareTo(now) > 0) {
                // double check 限流时间不为空，直接返回
                return;
            }
            if (requestNode == null) {
                // double check
                return;
            }
            // 请求统计操作
            if (requestNode.math(now)) {
                return;
            }
            // 请求限流
            unLockTime = now + requestNode.getLimitTime();
            message = requestNode.getMessage();

        } finally {
            // 解锁
            lock.unlock();
        }
    }

    /**
     * 异常限流计算操作
     */
    public void failLimitMath() {

        long now = System.currentTimeMillis();

        if (failNode == null) {
            // 没有请求限流配置，直接返回
            return;
        }
        // 加锁
        lock.lock();
        try {
            if (failNode == null) {
                // double check
                return;
            }
            if (unLockTime != null && unLockTime.compareTo(now) > 0 && failNode.getMessage().equals(message)) {
                // 已异常限流，无需重复操作
                return;
            }
            // 异常统计操作
            if (!failNode.math(now)) {
                // 请求限流
                unLockTime = now + failNode.getLimitTime();
                message = failNode.getMessage();
            }
        } finally {
            // 解锁
            lock.unlock();
        }
    }
}
